﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using Database.Classes;
using System.Collections;
using System.Collections.Generic;

//If planet is empty && fleets contains cs: check culture maybe colonize
//If planet is empty set fleet
//If planet is unknown initiate attack procedure, use transports & cs if win
//If planet is the same player set fleet and use cs
//if planet is enemy initiate attack proc, use transports & cs if win

public partial class StoredProcedures
{
    struct Fleet
    {
        public TimeSpan Span;
        public int Id;
        public int Owner;
        public int SId;
        public int PId;
        public int CS;
        public int TR;
        public int DS;
        public int CR;
        public int BS;
    }

    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void UpdateFleets()
    {
        int intervalTime, pp;
        double AttackBonus, DefBonus;
        try
        {
            intervalTime = int.Parse(GetConfigurationForOption("SmallUpdateInterval"));//in seconds
            AttackBonus = double.Parse(GetConfigurationForOption("AttackBonus"));
        }
        catch (Exception ex)
        {
            throw new Exception("SmallUpdateInterval", ex);
        }
        try
        {
            pp = int.Parse(GetConfigurationForOption("PPpointsFromCS"));
            DefBonus = double.Parse(GetConfigurationForOption("AttackBonus"));
        }
        catch (Exception ex)
        {
            throw new Exception("PPpointsFromCS", ex);
        }
        List<Fleet> fleets = new List<Fleet>();
        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Select * from fleets", conn))
            {
                SqlDataReader rdr = cmd.ExecuteReader();
                while (rdr.Read())
                {
                    DateTime dt = rdr.GetDateTime(11);
                    TimeSpan s = dt - DateTime.Now;
                    int fid = rdr.GetInt32(0);
                    int owner = int.Parse(rdr["OwnerID"].ToString());
                    int sId = int.Parse(rdr["ToSystem"].ToString());
                    int pId = int.Parse(rdr["ToPlanet"].ToString());
                    int cs = int.Parse(rdr["ColonyShips"].ToString());
                    int tr = int.Parse(rdr["Transports"].ToString());
                    int ds = int.Parse(rdr["Destroyers"].ToString());
                    int cr = int.Parse(rdr["Crusiers"].ToString());
                    int bs = int.Parse(rdr["Battleships"].ToString());
                    fleets.Add(new Fleet { Span = s, Id = fid, Owner = owner, SId = sId, PId = pId, CS = cs, TR = tr, DS = ds, CR = cr, BS = bs });
                }
            }
        }
        foreach (Fleet a in fleets)
        {
            ProcessFleet(a, intervalTime, AttackBonus, DefBonus, pp);
        }
    }

    private static void ProcessFleet(Fleet a, int intervalTime, double AttackBonus, double DefBonus, int pp)
    {
        TimeSpan s = a.Span;
        int fid = a.Id;
        int owner = a.Owner;
        int sId = a.SId;
        int pId = a.PId;
        int cs = a.CS;
        int tr = a.TR;
        int ds = a.DS;
        int cr = a.CR;
        int bs = a.BS;
        // InsertNews(8, DateTime.Now, "Ts: " + sId.ToString() + " PS:" + pId.ToString() + " " + s.TotalSeconds.ToString());
        if (s.TotalSeconds < intervalTime)
        {
            int FleetOwner = UserDefinedFunctions.FleetOwner(sId, pId);

            if (FleetOwner != owner && FleetOwner >= 1)//battle always come first
            {
                int AttackerAt, DefenderAt, AttackerDef, DefenderDef;
                int DefID = UserDefinedFunctions.FleetOwner(sId, pId);
                AttackerAt =  UserDefinedFunctions.GetPlayerInt(owner, "Attack").Value;
                DefenderAt = UserDefinedFunctions.GetPlayerInt(DefID, "Attack").Value;
                AttackerDef = UserDefinedFunctions.GetPlayerInt(owner, "Defense").Value;
                DefenderDef =  UserDefinedFunctions.GetPlayerInt(DefID, "Defense").Value;

                int AttackerPhy = (int)UserDefinedFunctions.GetPlayerFloat(owner, "Physics");
                int AttackerMath = (int)UserDefinedFunctions.GetPlayerFloat(owner, "Math");
                int DefenderPhy = (int)UserDefinedFunctions.GetPlayerFloat(DefID, "Physics");
                int DefenderMath = (int)UserDefinedFunctions.GetPlayerFloat(DefID, "Math");

                //get bonuses from artifacts
                if (UserDefinedFunctions.UsedArtifact(owner) != null)
                {
                    switch (UserDefinedFunctions.UsedArtifact(owner))
                    {
                        case "PG": AttackerPhy  += 7; break;
                        case "GG": AttackerPhy += 14; break;
                        case "ES": AttackerMath += 08; break;
                        case "PS": AttackerMath += 16; break;
                        case "AF": AttackerPhy += 15; AttackerMath += 15; break;
                    }
                }
                if (UserDefinedFunctions.UsedArtifact(DefID) != null)
                {
                    switch (UserDefinedFunctions.UsedArtifact(DefID))
                    {
                        case "PG": DefenderPhy += 7; break;
                        case "GG": DefenderPhy += 14; break;
                        case "ES": DefenderMath += 8; break;
                        case "PS": DefenderMath+= 16; break;
                        case "AF": DefenderPhy += 15; DefenderMath +=15; break;
                    }
                }
                Dictionary<string, int> fleetOnPlanet = UserDefinedFunctions.FleetOnPlanet(sId, pId);
                int defDs = fleetOnPlanet["Destroyers"];
                int defCr = fleetOnPlanet["Crusiers"];
                int defBs = fleetOnPlanet["Battleships"];
                double defSb = fleetOnPlanet["Starbase"];
                if (defDs + defCr + defBs + defSb > 0)//in case there is no fleet on planet do not start fight
                {
                    //and if win attack transports
                    int attCv, defCV; double attchance, winninglosses;
                    bool win = Equations.AttackProcedure(AttackerAt, AttackerDef, AttackerPhy, AttackerMath, ref ds, ref cr, ref bs,
                        DefenderAt, DefenderDef, DefenderPhy, DefenderMath, ref defDs, ref defCr, ref defBs, ref defSb, out attCv, out defCV, out attchance, out winninglosses);
                    InsertNews(8, DateTime.Now, "s:" + sId.ToString() + " p:" + pId.ToString() + " aCV:" + attCv.ToString() + " dCV:" + defCV.ToString() + " winner:" + win.ToString() + " loses:" + winninglosses.ToString());
                    if (win == true)
                    {

                        InsertNews(owner, DateTime.Now, "Congratulations! You have won battle on the orbit of: " + UserDefinedFunctions.SystemName(sId).Value + " #" + pId.ToString() + " against " + UserDefinedFunctions.PlayerName(DefID).ToString() + ".<br />\n" + "You gained " + defCV.ToString() + " experience.<br/>\n" +
                            "You lost about " + ((int)(winninglosses * 100)).ToString() + "% of your fleet.");
                        InsertNews(DefID, DateTime.Now, "Your fleet was defeated on the orbit of: " + UserDefinedFunctions.SystemName(sId).Value + " #" + pId.ToString() + " against " + UserDefinedFunctions.PlayerName(owner).ToString() + ".<br/>" +
                            "You killed about " + ((int)(winninglosses * 100)).ToString() + "% of enemy fleet.");
                        InsertBattle(owner, attCv, DefID, defCV, DateTime.Now, sId, pId, owner);
                        //Add fleet of attacker
                        SetExperience(owner, defCV);
                        FleetOwner = 0;
                    }
                    else
                    {
                        InsertNews(DefID, DateTime.Now, "Congratulations! Your defending forces have won battle on the orbit of: " + UserDefinedFunctions.SystemName(sId).Value + " #" + pId.ToString() + " against " + UserDefinedFunctions.PlayerName(owner).ToString() + ".<br />\n" + "You gained " + attCv.ToString() + " experience.<br/>" +
                            "You lost about " + ((int)(winninglosses * 100)).ToString() + "% of your fleet.");
                        InsertNews(owner, DateTime.Now, "Your fleet was defeated on the orbit of: " + UserDefinedFunctions.SystemName(sId).Value + " #" + pId.ToString() + " against " + UserDefinedFunctions.PlayerName(DefID).ToString() + ".<br/>" +
                            "You killed about " + ((int)(winninglosses * 100)).ToString() + "% of enemy fleet.");
                        InsertBattle(owner, attCv, DefID, defCV, DateTime.Now, sId, pId, DefID);
                        SetFleetWithCS(sId, pId, DefID, fleetOnPlanet["ColonyShips"], fleetOnPlanet["Transports"], defDs, defCr, defBs);
                        SetSbOnPlanet(sId, pId, defSb);
                        SetExperience(DefID, attCv);
                        RemoveFleet(fid);
                        return;
                    }
                }
            }

            bool CS = (cs != 0 ? true : false);
            bool TR = (tr != 0 ? true : false);
            bool UnknownPlanet = (UserDefinedFunctions.PlanetOwner(sId, pId).Value == 1 ? true : false);
            bool EnemyPlanet = (UserDefinedFunctions.PlanetOwner(sId, pId).Value != owner ? true : false);
            bool EmptyPlanet = UserDefinedFunctions.IsEmptyPlanet(sId, pId).Value;
            bool FleetExists = UserDefinedFunctions.FleetExists(sId, pId).Value;
            bool CanColonize = (UserDefinedFunctions.PlayerPlanets(owner).Value < UserDefinedFunctions.PlayerCulture(owner)).Value;
            bool SamePlayer = (UserDefinedFunctions.PlanetOwner(sId, pId).Value == owner);
            if (EmptyPlanet == true)
            {
                if (CanColonize == true && CS == true)
                {
                    ColonizePlanet(sId, pId, owner);
                    AddFleet(sId, pId, owner, tr, ds, cr, bs);
                    AddProductionPoints(sId, pId, (cs - 1) * pp);
                }
                else
                {
                    //if there is some fleet we should add it not delete
                    AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
                }
            }
            else if (SamePlayer == true)
            {
                AddFleet(sId, pId, owner, tr, ds, cr, bs);
                AddProductionPoints(sId, pId, cs * pp);
            }
            else if (UnknownPlanet == true || EnemyPlanet == true)
            {
                UseTransports(sId, pId, owner, cs, tr, ds, cr, bs);
                //if (CanColonize == true && TR == true)
                //{
                //    UseTransports(sId, pId, owner, cs, tr, ds, cr, bs);
                //}
                //else
                //    SetFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
            }


            //remove fleet
            RemoveFleet(fid);
        }
    }

    private static void SetSbOnPlanet(int sId, int pId, double defSb)
    {
        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Update Planets SET Starbase =  @sb Where SystemID = @sid and PlanetID = @pid", conn))
            {
                cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sId;
                cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pId;
                cmd.Parameters.Add("@sb", SqlDbType.Float).Value = defSb;

            }
        }
    }
    //If we come to this moment planet should be empty so just add fleet
    private static void UseTransports(int sId, int pId, int owner, int cs, int tr, int ds, int cr, int bs)
    {
        int pp = int.Parse(GetConfigurationForOption("PPpointsFromCS"));
        if (UserDefinedFunctions.IsEmptyPlanet(sId, pId) == false)
        {
            if (UserDefinedFunctions.PlayerPlanets(owner) < UserDefinedFunctions.PlayerCulture(owner))
            {
                //conquer the planet
                int pop = UserDefinedFunctions.PopulationOnPlanet(sId, pId);
                if (pop <= tr)
                {
                    ConquerPlanet(sId, pId, owner);
                    AddProductionPoints(sId, pId, cs * pp);
                    AddFleetWithCS(sId, pId, owner, 0, tr - pop, ds, cr, bs);
                }
            }
            else
            {
                //destroy pop
                KillPopOnPlanet(sId, pId, owner, ref tr);
                AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
            }
        }
        else
        {
            AddFleetWithCS(sId, pId, owner, cs, tr, ds, cr, bs);
        }
    }


    //[Microsoft.SqlServer.Server.SqlProcedure]
    //public static void AddFleet(int sid, int pid, int Owner, int tr, int ds, int cr, int bs)
    //{

    //    using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
    //    {
    //        conn.Open();
    //        using (SqlCommand cmd = new SqlCommand("Update Planets SET Transports = Transports + @s Where SystemID = @sid and PlanetID = @pid", conn))
    //        {
    //            cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sid;
    //            cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pid;
    //            cmd.Parameters.Add("@s", SqlDbType.Int).Value = tr;
    //            cmd.ExecuteNonQuery();
    //            cmd.CommandText = "Update Planets SET Destroyers = Destroyers + @s Where SystemID = @sid and PlanetID = @pid";
    //            cmd.Parameters["@s"].Value = ds;
    //            cmd.ExecuteNonQuery();
    //            cmd.CommandText = "Update Planets SET Crusiers = Crusiers + @s Where SystemID = @sid and PlanetID = @pid";
    //            cmd.Parameters["@s"].Value = cr;
    //            cmd.ExecuteNonQuery();
    //            cmd.CommandText = "Update Planets SET Battleships = Battleships + @s Where SystemID = @sid and PlanetID = @pid";
    //            cmd.Parameters["@s"].Value = bs;
    //            cmd.ExecuteNonQuery();
    //        }
    //    }
    //}
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void AddFleetWithCS(int sid, int pid, int OwnerID, int cs, int tr, int ds, int cr, int bs)
    {
        InsertNews(8, DateTime.Now, "Add fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerID.ToString());
        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Update Planets SET Transports = Transports + @s, FleetOwnerID = @oId Where SystemID = @sid and PlanetID = @pid", conn))
            {
                cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sid;
                cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pid;
                cmd.Parameters.Add("@s", SqlDbType.Int).Value = tr;
                cmd.Parameters.Add("@oId", SqlDbType.Int).Value = OwnerID;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Destroyers = Destroyers + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = ds;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Crusiers = Crusiers + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = cr;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Battleships = Battleships + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = bs;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET ColonyShips = ColonyShips + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = cs;
                cmd.ExecuteNonQuery();
            }
        }
    }
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void SetFleetWithCS(int sid, int pid, int OwnerID, int cs, int tr, int ds, int cr, int bs)
    {
        InsertNews(8, DateTime.Now, "Set fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerID.ToString());
        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Update Planets SET Transports =  @s, FleetOwnerID = @oId Where SystemID = @sid and PlanetID = @pid", conn))
            {
                cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sid;
                cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pid;
                cmd.Parameters.Add("@s", SqlDbType.Int).Value = tr;
                cmd.Parameters.Add("@oId", SqlDbType.Int).Value = OwnerID;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Destroyers = @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = ds;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Crusiers = @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = cr;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Battleships =  @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = bs;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET ColonyShips =  @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = cs;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Starbase = 0 Where SystemID = @sid and PlanetID = @pid";
                cmd.ExecuteNonQuery();
            }
        }
    }
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void AddFleet(int sid, int pid, int OwnerId, int tr, int ds, int cr, int bs)
    {
        InsertNews(8, DateTime.Now, "Add fleet with cs: sId: " + sid.ToString() + ", pID:" + pid.ToString() + " o:" + OwnerId.ToString());
        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Update Planets SET Transports = Transports + @s, FleetOwnerID = @oId Where SystemID = @sid and PlanetID = @pid", conn))
            {
                cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sid;
                cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pid;
                cmd.Parameters.Add("@oId", SqlDbType.Int).Value = OwnerId;
                cmd.Parameters.Add("@s", SqlDbType.Int).Value = tr;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Destroyers = Destroyers + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = ds;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Crusiers = Crusiers + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = cr;
                cmd.ExecuteNonQuery();
                cmd.CommandText = "Update Planets SET Battleships = Battleships + @s Where SystemID = @sid and PlanetID = @pid";
                cmd.Parameters["@s"].Value = bs;
                cmd.ExecuteNonQuery();
            }
        }
    }
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void AddProductionPoints(int sid, int pid, int pp)
    {

        using (SqlConnection conn = new SqlConnection(StaticMethods.ConnectionString()))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("Update Planets SET ProductionPoints = ProductionPoints + @s Where SystemID = @sid and PlanetID = @pid", conn))
            {
                cmd.Parameters.Add("@sid", SqlDbType.Int).Value = sid;
                cmd.Parameters.Add("@pid", SqlDbType.Int).Value = pid;
                cmd.Parameters.Add("@s", SqlDbType.Int).Value = pp;
                cmd.ExecuteNonQuery();
            }
        }
    }
};
